package aop02;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * Author:shixiaojun@itany.com
 * Date:2022/3/8 9:18
 * Version:1.0-SNAPSHOT
 */
public class LogInvocationHandler implements InvocationHandler {

    // 由于在实现交叉业务逻辑的时候,必须知道目标类是谁
    // 而目标类只有在具体调用时我们才知道是谁
    // 因此,我们可以限制调用者,在调用的时候必须将目标类传递进来
    // 此时调用者可以根据构造函数的方式进行调用
    // 只提供一个有参构造函数,其参数即为目标类
    // 定义目标类对象
    // 当调用者调用时会将目标类传递进来
    // 传递进来之后处理invoke时,可以获取到具体的目标类对象
    private Object target;

    public LogInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 交叉业务逻辑
     * @param proxy     代理类,完全没用
     * @param method    目标方法
     * @param args      目标方法的参数列表
     * @return          交叉业务逻辑的返回值,要求返回的必须是调用的方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 交叉业务逻辑具体实现代码
        System.out.println("在"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+"执行了"+method.getName()+"方法,方法的参数为:"+ Arrays.toString(args));
        // 在交叉业务逻辑中实现功能时不能改变原有功能
        // 必须获取到目标方法的返回值
        try {
            // 参数一:从中调用底层方法的对象
            // 即:方法所在的对象是谁,此处即为目标类对象
            // 参数二:可变长参数,用于方法调用的参数
            // 即:目标方法的参数列表
            Object result = method.invoke(target,args);
            System.out.println("方法运行完成,其返回值为:"+result);
            return result;
        } catch (IllegalAccessException e) {
            System.out.println("方法执行遇到了异常,异常为:"+e);
            throw e;
        } catch (IllegalArgumentException e) {
            System.out.println("方法执行遇到了异常,异常为:"+e);
            throw e;
        } catch (InvocationTargetException e) {
            System.out.println("方法执行遇到了异常,异常为:"+e);
            throw e;
        }
    }
}
